/* eslint-disable comma-dangle */
/* eslint-disable space-before-function-paren */
import View from './components/view'
import Link from './components/link'
// 为什么需要export一个vue引用
/**
 * 插件在打包的时候是肯定不希望把 vue 作为一个依赖包打进去的，
 * 但是呢又希望使用 Vue 对象本身的一些方法，此时就可以采用上边类似的做法，
 * 在 install 的时候把这个变量赋值 Vue ，这样就可以在其他地方使用 Vue
 * 的一些方法而不必引入 vue 依赖包（前提是保证 install 后才会使用）
 */
export let _Vue

export function install(Vue) {
  // 避免重复注册
  if (install.installed && _Vue === Vue) return
  install.installed = true
  // 存储Vue
  _Vue = Vue
  // 非空判断函数
  const isDef = (v) => v !== undefined

  const registerInstance = (vm, callVal) => {
    let i = vm.$options._parentVnode
    if (
      isDef(i) &&
      isDef((i = i.data)) &&
      isDef((i = i.registerRouteInstance))
    ) {
      i(vm, callVal)
    }
  }
  // 注入全局Mixin
  Vue.mixin({
    beforeCreate() {
      if (isDef(this.$options.router)) {
        // 引入router的根组件实例
        this._routerRoot = this
        // router实例
        this._router = this.$options.router
        // 路由初始化
        this._router.init(this)
        // 定义响应式的_route也就是$route对象，很重要
        Vue.util.defineReactive(this, '_route', this._router.history.current)
      } else {
        // 递归引用父类的_routerRoot实例
        this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
      }
      registerInstance(this, this)
    },
    destroyed() {
      registerInstance(this)
    },
  })
  // 原型属性
  Object.defineProperty(Vue.prototype, '$router', {
    get() {
      return this._routerRoot._router
    },
  })
  // 原型属性
  Object.defineProperty(Vue.prototype, '$route', {
    get() {
      return this._routerRoot._route
    },
  })
  // 注册全局组件RouterView、RouterLink
  Vue.component('RouterView', View)
  Vue.component('RouterLink', Link)
  // 合并策略
  const strats = Vue.config.optionMergeStrategies
  // use the same hook merging strategy for route hooks
  // 组件的路由钩子函数合并策略, beforeRouteEnter、beforeRouteLeave、beforeRouteUpdate
  strats.beforeRouteEnter =
    strats.beforeRouteLeave =
    strats.beforeRouteUpdate =
      strats.created
}
